package com.xuecheng.checkcode.service.impl;

import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.tea.TeaException;
import com.aliyun.teautil.Common;
import com.aliyun.teautil.models.RuntimeOptions;
import com.xuecheng.checkcode.exception.SmsSendFailedException;
import com.xuecheng.checkcode.model.CheckCodeResultDTO;
import com.xuecheng.checkcode.model.GenerateCheckCodeParamsDTO;
import com.xuecheng.checkcode.service.AbstractCheckCodeService;
import com.xuecheng.checkcode.service.CheckCodeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @author 勾新杰
 * @version 1.0
 * @description: 短信验证码服务实现
 * @date 2025/2/24 19:19
 */
@Slf4j
@Service("SmsCheckCodeService")
@RequiredArgsConstructor
public class SmsCheckCodeServiceImpl extends AbstractCheckCodeService implements CheckCodeService {

    /**
     * 短信客户端
     */
    private final Client smsClient;

    /**
     * 标签名
     */
    @Value("${xuecheng.aliyun.sms.sign-name}")
    private String signName;

    /**
     * 短信模版code
     */
    @Value("${xuecheng.aliyun.sms.template-code}")
    private String templateCode;

    private static final String KEY_PREFIX = "sms:";

    private static final Integer CODE_LENGTH = 6;

    private static final Integer EXPIRE_SECONDS = 300;

    /**
     * 设置验证码生成器
     *
     * @param checkCodeGenerator 生成器
     */
    @Resource(name = "NumberCheckCodeGenerator")
    @Override
    public void setCheckCodeGenerator(CheckCodeGenerator checkCodeGenerator) {
        this.checkCodeGenerator = checkCodeGenerator;
    }

    /**
     * 设置验证码key生成器
     *
     * @param keyGenerator key生成器
     */
    @Resource(name = "UUIDKeyGenerator")
    @Override
    public void setKeyGenerator(KeyGenerator keyGenerator) {
        this.keyGenerator = keyGenerator;
    }

    /**
     * 设置验证码存储
     *
     * @param checkCodeStore 验证码存储器
     */
    @Resource(name = "RedisCheckCodeStore")
    @Override
    public void setCheckCodeStore(CheckCodeStore checkCodeStore) {
        this.checkCodeStore = checkCodeStore;
    }

    /**
     * 生成验证码
     *
     * @param generateCheckCodeParamsDTO 验证码参数
     * @return 生成结果
     */
    @Override
    public CheckCodeResultDTO generate(GenerateCheckCodeParamsDTO generateCheckCodeParamsDTO) {
        GenerateResult result = generate(CODE_LENGTH, KEY_PREFIX, EXPIRE_SECONDS);
        sendToPhone(generateCheckCodeParamsDTO.getParam1(), result.getCode());
        return new CheckCodeResultDTO(result.getKey(), null);
    }

    /**
     * 发送验证码到手机
     *
     * @param phone 手机号
     * @param code  验证码
     */
    private void sendToPhone(String phone, String code) {
        SendSmsRequest sendSmsRequest = new SendSmsRequest()
                .setPhoneNumbers(phone) // 接收短信的手机号码
                .setSignName(signName) // 短信签名名称
                .setTemplateCode(templateCode) // 短信模板CODE
                .setTemplateParam("{\"code\":\"" + code + "\"}"); // 短信模板变量对应的实际值
        try {
            smsClient.sendSmsWithOptions(sendSmsRequest, new RuntimeOptions());
        } catch (TeaException error) {
            // 此处仅做打印展示，请谨慎对待异常处理，在工程项目中切勿直接忽略异常。
            // 错误 message
            log.error("错误 message: {}", error.getMessage());
            // 诊断地址
            System.out.println(error.getData().get("Recommend"));
            Common.assertAsString(error.message);
            throw new SmsSendFailedException();
        } catch (Exception _error) {
            TeaException error = new TeaException(_error.getMessage(), _error);
            // 此处仅做打印展示，请谨慎对待异常处理，在工程项目中切勿直接忽略异常。
            log.error("错误 message: {}", error.getMessage());
            // 诊断地址
            System.out.println(error.getData().get("Recommend"));
            Common.assertAsString(error.message);
            throw new SmsSendFailedException();
        }
    }
}
